iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0
生成式 AI

練習AI系列 第 5

文字 → JSON(更嚴格的結構化輸出與驗證)

  • 分享至 

  • xImage
  •  

新增/修改的程式碼

src/day4_text_to_json.js(新增)
// src/day4_text_to_json.js
import { openai } from "./aiClient.js";
import { PromptBuilder } from "./promptBuilder.js";
import { extractJson, validateBySchema } from "./jsonGuard.js";

/**

  • 新聞 → JSON 結構化摘要
  • Schema:
  • {
  • "title": string,
  • "summary": string,
  • "keywords": string[],
  • "category": string, // politics | tech | health | finance | sports | other
  • "date": string // YYYY-MM-DD
  • }
    */
    const schema = {
    type: "object",
    required: ["title", "summary", "keywords", "category", "date"],
    properties: {
    title: { type: "string" },
    summary: { type: "string" },
    keywords: { type: "object" }, // 注意會驗證是 array
    category: { type: "string" },
    date: { type: "string" }
    },
    };

export async function newsToJson(articleText) {
const pb = new PromptBuilder()
.setRole("你是一個新聞編輯助手")
.setGoal("將輸入的新聞文章轉換為結構化 JSON 摘要")
.addConstraint("輸出必須是純 JSON,不要有多餘文字或 Markdown")
.addConstraint("keywords 請為 3~5 個字詞陣列")
.addConstraint("category 必須是 politics, tech, health, finance, sports, other 其中之一")
.setJsonSchema(schema)
.setUserInput(articleText);

const res = await openai.chat.completions.create({
model: "gpt-4o-mini",
temperature: 0.2,
messages: pb.toMessages(),
});

const raw = res.choices?.[0]?.message?.content ?? "";
const obj = extractJson(raw);
const check = validateBySchema(obj, schema);

if (!check.ok) {
throw new Error("JSON 不符合 schema:" + check.errors.join("; "));
}

return obj;
}
index.js(更新)
// index.js
import { englishTeacher, codeReview, sentimentClassify } from "./src/day3_prompt_engineering.js";
import { newsToJson } from "./src/day4_text_to_json.js";

const args = Object.fromEntries(
process.argv.slice(2).reduce((acc, cur, i, arr) => {
if (cur.startsWith("--")) {
const key = cur.replace(/^--/, "");
const val = arr[i + 1] && !arr[i + 1].startsWith("--") ? arr[i + 1] : true;
acc.push([key, val]);
}
return acc;
}, [])
);

async function main() {
const task = args.task || "teacher";

if (task === "teacher") {
const input = args.text || "He go to school every day.";
const out = await englishTeacher(input);
console.log("\n=== 英文老師 ===\n");
console.log(out);

} else if (task === "review") {
const sample =
function sum(arr){ let s = 0; for (let i=0;i<arr.length;i++){ s += arr[i] } return s };
const out = await codeReview(sample, "javascript");
console.log("\n=== 程式碼審查 ===\n");
console.log(out);

} else if (task === "sentiment") {
const text = args.text || "今天心情糟透了,事情一團亂。";
const out = await sentimentClassify(text);
console.log("\n=== 情緒分類(JSON) ===\n");
console.log(out);

} else if (task === "json_summary") {
const article = args.text || 台北市今天宣布推出全新的智慧交通系統, 透過 AI 與大數據分析來優化紅綠燈號誌,預計將能減少 20% 的交通壅塞。;
const out = await newsToJson(article);
console.log("\n=== 新聞 JSON 摘要 ===\n");
console.log(out);

} else {
console.log("未知任務,請使用 --task teacher | review | sentiment | json_summary");
}
}

main().catch((e) => {
console.error("發生錯誤:", e.message);
process.exit(1);
});
package.json(新增 Script)
{
"scripts": {
"day4:json": "node index.js --task json_summary --text "OpenAI 公布新模型,將大幅提升效能與效率。""
}
}
如何執行

跑新聞 → JSON 摘要

npm run day4:json --silent
輸出結果(範例):

{
"title": "台北市啟動智慧交通系統",
"summary": "台北市政府宣布推出 AI 與大數據驅動的智慧交通系統,預計能有效減少交通壅塞 20%。",
"keywords": ["智慧交通", "AI", "大數據", "紅綠燈優化"],
"category": "tech",
"date": "2025-09-04"
}


上一篇
提示工程(Prompt Engineering)
下一篇
多輪對話(Chat History)
系列文
練習AI11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言